home *** CD-ROM | disk | FTP | other *** search
- /* The event_stream interface for tty's.
- Copyright (C) 1994, 1995 Board of Trustees, University of Illinois
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not in FSF. */
-
- #include <config.h>
- #include "lisp.h"
-
- #include "blocktype.h"
- #include "device.h"
- #include "device-tty.h"
- #include "events.h"
- #include "frame.h"
- #include "process.h"
-
- #include "sysproc.h"
- #include "syswait.h"
- #include "systime.h"
-
- /* Mask of bits indicating the descriptors that we wait for input on */
- extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
- extern SELECT_TYPE process_only_mask, device_only_mask;
-
- extern Lisp_Object Qdelete_device;
-
- static struct event_stream *tty_event_stream;
-
-
- /************************************************************************/
- /* timeout events */
- /************************************************************************/
-
- /* The pending timers are stored in an ordered list, where the first timer
- on the list is the first one to fire. Times recorded here are
- absolute. */
- static struct low_level_timeout *tty_timer_queue;
-
- static int
- emacs_tty_add_timeout (EMACS_TIME time)
- {
- return add_low_level_timeout (&tty_timer_queue, time);
- }
-
- static void
- emacs_tty_remove_timeout (int id)
- {
- remove_low_level_timeout (&tty_timer_queue, id);
- }
-
- static void
- tty_timeout_to_emacs_event (struct Lisp_Event *emacs_event)
- {
- emacs_event->event_type = timeout_event;
- emacs_event->timestamp = 0; /* #### */
- emacs_event->event.timeout.interval_id =
- pop_low_level_timeout (&tty_timer_queue, 0);
- }
-
-
-
- static int
- emacs_tty_event_pending_p (int user_p)
- {
- if (!user_p)
- {
- EMACS_TIME sometime;
- /* see if there's a pending timeout. */
- EMACS_GET_TIME (sometime);
- if (tty_timer_queue &&
- EMACS_TIME_EQUAL_OR_GREATER (sometime, tty_timer_queue->time))
- return 1;
- }
-
- return poll_fds_for_input (user_p ? device_only_mask :
- non_fake_input_wait_mask);
- }
-
- static struct device *
- find_device_from_fd (int fd)
- {
- Lisp_Object rest;
-
- DEVICE_LOOP (rest)
- {
- struct device *d;
-
- assert (DEVICEP (XCAR (rest)));
- d = XDEVICE (XCAR (rest));
- if (DEVICE_IS_TTY (d) && fileno (DEVICE_TTY_DATA (d)->infd) == fd)
- return d;
- }
-
- return 0;
- }
-
- int
- read_event_from_tty_or_stream_desc (struct Lisp_Event *event,
- struct device *d, int fd)
- {
- unsigned char ch;
- int nread;
-
- nread = read (fd, &ch, 1);
- if (nread == 0)
- {
- Lisp_Object device;
- XSETDEVICE (device, d);
- /* deleting the device might not be safe right now ... */
- Fenqueue_eval_event (Qdelete_device, device);
- /* but we definitely need to unselect it to avoid infinite
- loops reading EOF's */
- Fdevice_disable_input (device);
- }
- else if (nread > 0)
- {
- character_to_event (ch, event, d);
- event->channel = DEVICE_SELECTED_FRAME (d);
- return 1;
- }
- else
- {
- /* #### What to do if there's an error? */
- }
- return 0;
- }
-
- int
- maybe_read_quit_event (struct Lisp_Event *event)
- {
- /* A C-g that came from `sigint_happened' will always come from the
- controlling terminal. If that doesn't exist, however, then the
- user manually sent us a SIGINT, and we pretend the C-g came from
- the selected-device. */
- struct device *d;
-
- if (DEVICEP (Vcontrolling_terminal) &&
- DEVICE_LIVE_P (XDEVICE (Vcontrolling_terminal)))
- d = XDEVICE (Vcontrolling_terminal);
- else
- d = XDEVICE (Fselected_device ());
-
- if (sigint_happened)
- {
- int ch = DEVICE_QUIT_CHAR (d);
- sigint_happened = 0;
- Vquit_flag = Qnil;
- character_to_event (ch, event, d);
- event->channel = DEVICE_SELECTED_FRAME (d);
- return 1;
- }
- return 0;
- }
-
- static void
- emacs_tty_next_event (struct Lisp_Event *emacs_event)
- {
- while (1)
- {
- int ndesc;
- int i;
- SELECT_TYPE temp_mask = input_wait_mask;
- EMACS_TIME time_to_block;
- EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
-
- if (!get_low_level_timeout_interval (tty_timer_queue, &time_to_block))
- /* no timer events; block indefinitely */
- pointer_to_this = 0;
- else
- {
- EMACS_TIME_TO_SELECT_TIME (time_to_block, select_time_to_block);
- pointer_to_this = &select_time_to_block;
- }
-
- ndesc = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
- if (ndesc > 0)
- {
- /* Look for a TTY event */
- for (i = 0; i < MAXDESC; i++)
- {
- /* To avoid race conditions (among other things, an infinite
- loop when called from Fdiscard_input()), we must return
- user events ahead of process events. */
- if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &device_only_mask))
- {
- struct device *d = find_device_from_fd (i);
-
- assert (d);
- if (read_event_from_tty_or_stream_desc (emacs_event, d, i))
- return;
- }
- }
-
- /* Look for a process event */
- for (i = 0; i < MAXDESC; i++)
- {
- if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &process_only_mask))
- {
- Lisp_Object process;
- struct Lisp_Process *p =
- get_process_from_input_descriptor (i);
-
- assert (p);
- XSETPROCESS (process, p);
- emacs_event->event_type = process_event;
- emacs_event->timestamp = 0; /* #### */
- emacs_event->event.process.process = process;
- return;
- }
- }
-
- /* We might get here when a fake event came through a signal. */
- /* Return a dummy event, so that a cycle of the command loop will
- occur. */
- drain_signal_event_pipe ();
- emacs_event->event_type = eval_event;
- emacs_event->event.eval.function = Qidentity;
- emacs_event->event.eval.object = Qnil;
- return;
- }
- else if (ndesc == 0) /* timeout fired */
- {
- tty_timeout_to_emacs_event (emacs_event);
- return;
- }
- }
- }
-
- static void
- emacs_tty_handle_magic_event (struct Lisp_Event *emacs_event)
- {
- /* Nothing to do currently */
- }
-
-
- static void
- emacs_tty_select_process (struct Lisp_Process *process)
- {
- /* Nothing to do currently */
- }
-
- static void
- emacs_tty_unselect_process (struct Lisp_Process *process)
- {
- /* Nothing to do currently */
- }
-
- static void
- emacs_tty_select_device (struct device *d)
- {
- /* Nothing to do currently */
- }
-
- static void
- emacs_tty_unselect_device (struct device *d)
- {
- /* Nothing to do currently */
- }
-
- static void
- emacs_tty_quit_p (void)
- {
- /* Nothing to do currently because QUIT is handled through SIGINT.
- This could change. */
- }
-
-
- /************************************************************************/
- /* initialization */
- /************************************************************************/
-
- void
- vars_of_event_tty (void)
- {
- tty_event_stream =
- (struct event_stream *) xmalloc (sizeof (struct event_stream));
-
- tty_event_stream->event_pending_p = emacs_tty_event_pending_p;
- tty_event_stream->next_event_cb = emacs_tty_next_event;
- tty_event_stream->handle_magic_event_cb = emacs_tty_handle_magic_event;
- tty_event_stream->add_timeout_cb = emacs_tty_add_timeout;
- tty_event_stream->remove_timeout_cb = emacs_tty_remove_timeout;
- tty_event_stream->select_device_cb = emacs_tty_select_device;
- tty_event_stream->unselect_device_cb = emacs_tty_unselect_device;
- tty_event_stream->select_process_cb = emacs_tty_select_process;
- tty_event_stream->unselect_process_cb = emacs_tty_unselect_process;
- tty_event_stream->quit_p_cb = emacs_tty_quit_p;
- }
-
- void
- init_event_tty_late (void)
- {
- event_stream = tty_event_stream;
- }
-